﻿using System;
using System.Globalization;
using ChessKit.Properties;

namespace ChessKit.Logic
{
	public struct Move
	{
		public ushort Index { get; private set; }
		public Square From { get { return (byte)(Index & 0xFF); } }
		public Square To { get { return (byte)(Index >> 8); } }

		public Move(int index)
			: this()
		{
			if ((index & 0x8888) != 0)
				throw new ArgumentOutOfRangeException();
			Index = (ushort)index;
		}
		public Move(ushort index)
			: this()
		{
			Index = index;
		}
		public Move(Square fromSquare, Square toSquare)
			: this()
		{
			Index = (ushort)(fromSquare | (toSquare << 8));
		}
		public Move([NotNull] string fromSquare, [NotNull] string toSquare)
			: this()
		{
			Index = (ushort)(Square.Parse(fromSquare) | (Square.Parse(toSquare) << 8));
		}

		#region ' Equality '

		public bool Equals(Move other)
		{
			return Index == other.Index;
		}

		public override bool Equals(object obj)
		{
			if (ReferenceEquals(null, obj)) return false;
			return obj is Move && Equals((Move)obj);
		}

		public override int GetHashCode()
		{
			return Index;
		}

		public static bool operator ==(Move left, Move right)
		{
			return left.Equals(right);
		}

		public static bool operator !=(Move left, Move right)
		{
			return !left.Equals(right);
		}

		#endregion

		/// <summary>Returns CAN move</summary>
		public override string ToString()
		{
			return string.Format(
			  CultureInfo.InvariantCulture, "{0}-{1}", From, To);
		}
		/// <summary>Parse CAN move</summary>
		public static Move Parse(string canString)
		{
			if (string.IsNullOrEmpty(canString)) throw new ArgumentException("should not be null or empty", "canString");
			if (canString.Length == 5)
				return new Move(
				  Square.Parse(canString.Substring(0, 2)),
				  Square.Parse(canString.Substring(3, 2)));
			if (canString.Length != 7) throw new ArgumentOutOfRangeException("canString");
			Piece piece;
			if (!canString[6].TryEnglishSymbolToPiece(out piece))
				throw new ArgumentOutOfRangeException("canString");
			return new Move(
				Square.Parse(canString.Substring(0, 2)),
				Square.Parse(canString.Substring(3, 2)));
		}
	}
}